import * as React from 'react';
import {
  PureComponent,
  PropTypes
} from 'react';
import * as cx from 'classnames';
import {findDOMNode} from 'react-dom';
import {
  HEADINGS,
  INLINE_STYLES,
  BLOCK_LISTS
} from './constants';
import {
  Dropdown,
  Button,
  ButtonGroup,
  MenuItem
} from 'react-bootstrap';
import PopOverButton from './popover-button';
import * as Input from 'formsy-react-components/release/input';

const DEFAULT_NODE = 'paragraph';

export default class Toolbar extends PureComponent {

  constructor(props) {
    super(props);

    this.setLink = this.setLink.bind(this);
    this.focusEditor = this.focusEditor.bind(this);
    this.renderLinkPopOver = this.renderLinkPopOver.bind(this);
  }


  renderReDoUnDo() {
    const {editorState} = this.props;
    const canUndo = editorState.getUndoStack().size !== 0;
    const canRedo = editorState.getRedoStack().size !== 0;

    return (
      <ButtonGroup>
        <Button
          onClick={this.undo}
          disabled={!canUndo}
        >
          <i className="fa fa-undo" />
        </Button>
        <Button
          onClick={this.redo}
          disabled={!canRedo}
        >
          <i className="fa fa-repeat" />
        </Button>
      </ButtonGroup>
    );
  }

  hasMark(type) {
    const { state } = this.props;
    return state.marks.some(mark => mark.type == type)
  }

  hasBlock(type) {
    const { state } = this.props;
    return state.blocks.some(node => node.type == type)
  }

  getLink() {
    const { state } = this.props;
    return state.inlines.find(inline => inline.type == 'link');
  }


  setLink(href) {
    const {
      state,
      onChange
    } = this.props;
    const link = this.getLink();

    if (link) {
      if (href) {
        onChange(
          state
            .transform()
            .unwrapInline('link')
            .wrapInline({
              type: 'link',
              data: { href }
            })
            .collapseToEnd()
            .apply()
        )
      } else {
        onChange(
          state
            .transform()
            .unwrapInline('link')
            .apply()
        )
      }
    } else if (state.isExpanded) {
      return onChange(
        state
          .transform()
          .wrapInline({
            type: 'link',
            data: { href }
          })
          .collapseToEnd()
          .apply()
      );
    }
  }

  toggleBlock(type) {
    let {
      state,
      onChange
    } = this.props;
    let transform = state.transform()
    const { document } = state

    // Handle everything but list buttons.
    if (type != 'bulleted-list' && type != 'numbered-list') {
      const isActive = this.hasBlock(type);
      const isList = this.hasBlock('list-item');

      if (isList) {
        transform = transform
          .setBlock(isActive ? DEFAULT_NODE : type)
          .unwrapBlock('bulleted-list')
          .unwrapBlock('numbered-list')
      }

      else {
        transform = transform
          .setBlock(isActive ? DEFAULT_NODE : type)
      }
    }

    // Handle the extra wrapping required for list buttons.
    else {
      const isList = this.hasBlock('list-item');
      const isType = state.blocks.some((block) => {
        return !!document.getClosest(block, parent => parent.type == type)
      });

      if (isList && isType) {
        transform = transform
          .setBlock(DEFAULT_NODE)
          .unwrapBlock('bulleted-list')
          .unwrapBlock('numbered-list')
      } else if (isList) {
        transform = transform
          .unwrapBlock(type == 'bulleted-list' ? 'numbered-list' : 'bulleted-list')
          .wrapBlock(type)
      } else {
        transform = transform
          .setBlock('list-item')
          .wrapBlock(type)
      }
    }

    state = transform.apply();
    onChange(state);
  }

  toggleMark(type) {
    let {
      state,
      onChange
    } = this.props;

    state = state
      .transform()
      .toggleMark(type)
      .apply();

    onChange(state);
  }

  focusEditor() {
    const focusEditor = this.props.focusEditor;
    setTimeout(() => focusEditor(), 50);
  }


  renderHeading() {
    let headingActive = false;


    const menu = (
      <Dropdown.Menu>
        {HEADINGS.map((heading, key) => (
          <MenuItem
            active={this.hasBlock(heading.type) && (headingActive = true)}
            key={key}
            onSelect={() => {
              this.toggleBlock(heading.type);
              this.focusEditor();
            }}
          >{heading.label}</MenuItem>
        ))}
      </Dropdown.Menu>
    );

    return (
      <Dropdown
        id="editor-pick-header"
      >
        <Dropdown.Toggle
          className={cx({
            active: headingActive
          })}
        >
          <i className="fa fa-header" />
        </Dropdown.Toggle>
        {menu}
      </Dropdown>
    );
  }

  renderLinkPopOver() {
    let href = '';
    const link = this.getLink();

    if (link) {
      href = link.data.get('href');
    }

    return (
      <div className="form-group m-b-none">
        <Input
          name="link"
          placeholder="http://example.com/"
          value={href || ''}
          layout="elementOnly"
        />
      </div>
    );
  }

  renderLinkButtons() {
    const {state} = this.props;
    const link = this.getLink();
    const shouldShowLinkButton = link || state.isExpanded;


    return (
      <ButtonGroup>
        <PopOverButton
          disabled={!shouldShowLinkButton}
          onDismiss={this.focusEditor}
          onSubmit={(model) => {
            const href = model.link;
            this.setLink(href);
          }}
          icon="fa fa-link"
          bodyRender={this.renderLinkPopOver}
        />
        <Button
          disabled={!link}
          onMouseDown={() => this.setLink(null)}
        >
          <i className="fa fa-cut" />
        </Button>
      </ButtonGroup>
    );
  }

  render() {
    const state = this.props.state;
    const { document } = state;

    return (
      <div className="btn-toolbar m-b-sm btn-editor">
        {this.renderHeading()}

        <ButtonGroup>
          {INLINE_STYLES.map((inline, key) => (
            <Button
              key={key}
              onMouseDown={(e) => {
                e.preventDefault();
                this.toggleMark(inline.type);
              }}
              active={this.hasMark(inline.type)}
            >
              <i className={inline.icon} />
            </Button>
          ))}
        </ButtonGroup>

        <ButtonGroup>
          {BLOCK_LISTS.map((item, key) => (
            <Button
              key={key}
              active={
                ~['numbered-list', 'bulleted-list'].indexOf(item.type)
                ? state.blocks.some(block => !!document.getClosest(block, parent => parent.type == item.type))
                : this.hasBlock(item.type)
              }
              onMouseDown={e => {
                e.preventDefault();
                this.toggleBlock(item.type)
              }}
            ><i className={item.icon} /></Button>
          ))}
        </ButtonGroup>

        {this.renderLinkButtons()}
      </div>
    );
  }
}